package io.ouka.jvm.hotspot.selfread.domain;

import io.ouka.jvm.hotspot.selfread.constant.FinalConstant;
import io.ouka.jvm.hotspot.selfread.read.AbstractReader;
import io.ouka.jvm.hotspot.selfread.util.DataTranslate;
import sun.rmi.runtime.Log;

import java.util.HashMap;
import java.util.Map;

import static io.ouka.jvm.hotspot.selfread.constant.ConstantPoolConstants.*;

/**
 * @author Ouka
 */
public class ConstantPool {
    private int[] tag;//标识类型
    private byte[] index;
    private int length;
    private Map<Integer, Object> dataMap ;

    public String getClassName(int index){
        int classIndex = (int) dataMap.get(index);
        return (String) dataMap.get(classIndex);
    }

    public String getDescriptorNameByMethodInfo(int operand) {
        int i = (int) getDataMap().get(operand);
        int nameAndTypeIndex = i & 0xff;
        int data = (int) getDataMap().get(nameAndTypeIndex);
        i = data & 0xFF;
        return (String) getDataMap().get(i);
    }

    public String getMethodNameByMethodInfo(int operand) {
        int i = (int) getDataMap().get(operand);
        int nameAndTypeIndex = i & 0xff;
        int data = (int) getDataMap().get(nameAndTypeIndex);
        i = data >> 16;
        return (String) getDataMap().get(i);
    }

    public String getClassNameByFieldInfo(int index) {
        int data = (int) getDataMap().get(index);
        int classIndex = data >> 16;
        int classNameIndex = (int) getDataMap().get(classIndex);
        return (String) getDataMap().get(classNameIndex);
    }

    public String getFieldName(int index) {
        int data = (int) getDataMap().get(index);
        int i = data & 0xFF;
        int nameAndType = (int) getDataMap().get(i);
        i = nameAndType >> 16;

        return (String) getDataMap().get(i);
    }

    public int[] getTag() {
        return tag;
    }

    public void setTag(int[] tag) {
        this.tag = tag;
    }

    public byte[] getIndex() {
        return index;
    }

    public int getLength() {
        return length;
    }

    public void setIndex(byte[] index) {
        this.index = index;
    }

    public void setLength(int length) {
        this.length = length;
        index = new byte[length];
        dataMap = new HashMap<>(length);
        tag = new int[length];
    }

    public Map<Integer, Object> getDataMap() {
        return dataMap;
    }

    public void setDataMap(Map<Integer, Object> dataMap) {
        this.dataMap = dataMap;
    }

    public void parse() {
        // 这块是根据
        int readIndex = 0;
        byte[] byteU1 = new byte[1];
        byte[] byteU2 = new byte[2];
        byte[] byteU4 = new byte[4];
        byte[] byteU8 = new byte[8];
        for (int i = 1; i < length; i++) {

            System.arraycopy(index, readIndex, byteU1, 0, 1);
            readIndex++;
            AbstractReader.addIndex(FinalConstant.u1);
            switch (byteU1[0]) {
                case JVM_CONSTANT_Utf8://*  tag=1   tag(1字节)|length(2字节)|byte(length字节)
                    tag[i-1]=JVM_CONSTANT_Utf8;
                    System.arraycopy(index, readIndex, byteU2, 0, FinalConstant.u2);
                    readIndex+=FinalConstant.u2;
                    AbstractReader.addIndex(FinalConstant.u2);
                    int len = DataTranslate.byteToUnsignedShort(byteU2);
                    byte[] bytes = new byte[len];
                    System.arraycopy(index, readIndex, bytes, 0, len);
                    readIndex+=len;
                    AbstractReader.addIndex(len);
                    dataMap.put(i, new String(bytes));

                    System.out.println("第"+i+"个元素解析为 JVM_CONSTANT_Utf8 tag--1 值为"+dataMap.get(i));
                    break;
                case JVM_CONSTANT_Unicode:
                    tag[i-1]=JVM_CONSTANT_Unicode;
                    break;
                case JVM_CONSTANT_Integer://*  tag=3 tag(1字节)|bytes(4字节)
                    tag[i-1]=JVM_CONSTANT_Integer;
                    break;
                case JVM_CONSTANT_Float://*  tag=4 tag(1字节)｜bytes(4字节)
                    tag[i-1]=JVM_CONSTANT_Float;
                    //2
                    break;
                case JVM_CONSTANT_Long://* tag=5  tag(1字节)|bytes(8字节)
                    tag[i-1]=JVM_CONSTANT_Long;
                    //2
                    System.arraycopy(index, readIndex, byteU8, 0, FinalConstant.u8);
                    readIndex+=FinalConstant.u8;
                    AbstractReader.addIndex(FinalConstant.u8);
//                    dataMap.put(i,);
                    dataMap.put(i,byteU8);
                    try {
                        System.out.println("第"+i+"个元素解析为 JVM_CONSTANT_Long tag--5 值为"+ DataTranslate.bytes2long(byteU8));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case JVM_CONSTANT_Double://* tag=6 tag(1字节)｜bytes(8字节)
                    tag[i-1]=JVM_CONSTANT_Double;
                    //2
                    System.arraycopy(index, readIndex, byteU8, 0, FinalConstant.u8);
                    readIndex+=FinalConstant.u8;
                    AbstractReader.addIndex(FinalConstant.u8);
                    dataMap.put(i,DataTranslate.bytesToDouble(byteU8,false));
                    System.out.println("第"+i+"个元素解析为 JVM_CONSTANT_Double tag--6 值为"+dataMap.get(i));
                    break;
                case JVM_CONSTANT_Class://*tag=7 tag(1字节)|index(2字节)
                    tag[i-1]=JVM_CONSTANT_Class;
                    System.arraycopy(index, readIndex, byteU2, 0, FinalConstant.u2);
                    readIndex+=2;
                    AbstractReader.addIndex(FinalConstant.u2);
                    dataMap.put(i,DataTranslate.byteToUnsignedShort(byteU2));
                    System.out.println("第"+i+"个元素解析为 JVM_CONSTANT_Class tag--7 常量池索引位置"+dataMap.get(i));
                    break;

                case JVM_CONSTANT_String://*tag=8 tag(1字节)|index(2字节)
                    tag[i-1]=JVM_CONSTANT_String;
                    System.arraycopy(index, readIndex, byteU2, 0, FinalConstant.u2);
                    readIndex+=2;
                    AbstractReader.addIndex(FinalConstant.u2);
                    dataMap.put(i,DataTranslate.byteToUnsignedShort(byteU2));
                    System.out.println("第"+i+"个元素解析为 JVM_CONSTANT_String tag--8 常量池索引位置"+dataMap.get(i));
                    break;
                case JVM_CONSTANT_Fieldref://* tag=9 tag(1字节)|index(2字节)｜index(2字节)
                    tag[i-1]=JVM_CONSTANT_Fieldref;
                    //first index
                    System.arraycopy(index, readIndex, byteU2, 0, FinalConstant.u2);
                    int filedFirstIndex = DataTranslate.byteToUnsignedShort(byteU2);
                    readIndex+=2;
                    AbstractReader.addIndex(FinalConstant.u2);
                    System.arraycopy(index, readIndex, byteU2, 0, FinalConstant.u2);
                    int filedSecondIndex = DataTranslate.byteToUnsignedShort(byteU2);
                    readIndex+=2;
                    AbstractReader.addIndex(FinalConstant.u2);

                    dataMap.put(i, filedFirstIndex << 16 | filedSecondIndex);
                    System.out.println("第"+i+"个元素解析为 JVM_CONSTANT_Fieldref tag--9 内容0x"+Integer.toHexString((Integer) dataMap.get(i)));
                    break;
                case JVM_CONSTANT_Methodref://* tag=10   tag(1字节)|index(2字节)|index(2字节)
                    tag[i-1]=JVM_CONSTANT_Methodref;
                    //first index
                    System.arraycopy(index, readIndex, byteU2, 0, FinalConstant.u2);
                    int methodRefFirstIndex = DataTranslate.byteToUnsignedShort(byteU2);
                    readIndex+=2;
                    AbstractReader.addIndex(FinalConstant.u2);
                    System.arraycopy(index, readIndex, byteU2, 0, FinalConstant.u2);
                    int methodRefSecondIndex = DataTranslate.byteToUnsignedShort(byteU2);
                    readIndex+=2;
                    AbstractReader.addIndex(FinalConstant.u2);
                    dataMap.put(i, methodRefFirstIndex << 16 | methodRefSecondIndex);
                    System.out.println("第"+i+"个元素解析为 JVM_CONSTANT_Methodref tag--10 内容0x"+Integer.toHexString((Integer) dataMap.get(i)));
                    break;
                case JVM_CONSTANT_InterfaceMethodref://* tag=11   tag(1字节)|index(2字节)|index(2字节)
                    tag[i-1]=JVM_CONSTANT_InterfaceMethodref;
                    break;
                case JVM_CONSTANT_NameAndType://* tag=12   tag(1字节)|index(2字节)|index(2字节)
                    tag[i-1]=JVM_CONSTANT_NameAndType;
                    //first index
                    System.arraycopy(index, readIndex, byteU2, 0, FinalConstant.u2);
                    int nameAndTypeFirstIndex = DataTranslate.byteToUnsignedShort(byteU2);
                    readIndex+=2;
                    AbstractReader.addIndex(FinalConstant.u2);
                    System.arraycopy(index, readIndex, byteU2, 0, FinalConstant.u2);
                    int nameAndTypeSecondIndex = DataTranslate.byteToUnsignedShort(byteU2);
                    readIndex+=2;
                    AbstractReader.addIndex(FinalConstant.u2);
                    dataMap.put(i, nameAndTypeFirstIndex << 16 | nameAndTypeSecondIndex);
                    System.out.println("第"+i+"个元素解析为 JVM_CONSTANT_NameAndType tag--12 内容0x"+Integer.toHexString((Integer) dataMap.get(i)));
                    break;
                case JVM_CONSTANT_MethodHandle:
                    tag[i-1]=JVM_CONSTANT_MethodHandle;
                    break;
                case JVM_CONSTANT_MethodType:
                    tag[i-1]=JVM_CONSTANT_MethodType;
                    break;
                case JVM_CONSTANT_InvokeDynamic:
                    tag[i-1]=JVM_CONSTANT_InvokeDynamic;
                    break;
                default:
                    System.out.println(byteU1[0]);
                    throw new IllegalArgumentException("unknow type");
            }
        }

    }
}
